// Effective C++ 条款19：设计class犹如设计type
// 核心思想
// 当你创建一个新的class时，你实际上是在定义一个新的type（类型）。
// 因此，你应该像语言设计者那样思考，考虑这个新类型的完整行为、接口、实现和与其他类型的交互方式。

// 设计class时需要考虑的问题
// 1. 对象的创建与销毁
// 关键问题：

// 对象如何被创建和销毁？
// 构造函数和析构函数需要做什么？
// 内存分配和释放如何管理？
// 是否允许拷贝和移动？
class String
{
public:
    // 构造函数
    String();                          // 默认构造
    explicit String(const char *text); // 从C字符串构造
    String(const String &rhs);         // 拷贝构造
    String(String &&rhs) noexcept;     // 移动构造 (C++11)

    // 析构函数
    ~String(); // 负责释放资源

    // 赋值操作
    String &operator=(const String &rhs);     // 拷贝赋值
    String &operator=(String &&rhs) noexcept; // 移动赋值 (C++11)
};

// 2. 对象的初始化与赋值
// 关键问题：

// 初始化和赋值有什么区别？
// 应该支持哪些形式的初始化？
// 隐式转换是否合适？
class Rational
{
public:
    // 支持从整数初始化，但防止隐式转换
    explicit Rational(int numerator = 0, int denominator = 1);

    // 允许从另一个Rational对象初始化
    Rational(const Rational &rhs);

    // 赋值操作
    Rational &operator=(const Rational &rhs);
};

// 使用
Rational r1;        // 默认构造
Rational r2(22, 7); // 带参数构造
// Rational r3 = 42;     // 错误：explicit防止隐式转换
Rational r4 = r2; // 拷贝构造
r1 = r2;          // 赋值

// 3. 对象的值传递
// 关键问题：

// 对象被值传递时意味着什么？
// 拷贝的成本是多少？
// 是否应该支持移动语义？
class Widget
{
public:
    // 如果拷贝成本高，考虑删除拷贝操作
    Widget(const Widget &) = delete;
    Widget &operator=(const Widget &) = delete;

    // 支持移动操作
    Widget(Widget &&rhs) noexcept;
    Widget &operator=(Widget &&rhs) noexcept;
};

// 4. 合法值的约束
// 关键问题：

// 对象的哪些值是合法的？
// 如何处理非法值？
// 是否需要不变式（invariants）？
class Date
{
public:
    Date(int year, int month, int day)
    {
        if (month < 1 || month > 12)
            throw std::invalid_argument("Month must be between 1 and 12");
        if (day < 1 || day > daysInMonth(year, month))
            throw std::invalid_argument("Invalid day for given month and year");

        this->year = year;
        this->month = month;
        this->day = day;
    }

private:
    int year, month, day;

    static int daysInMonth(int year, int month);
};

// 5. 类的继承关系
// 关键问题：

// 这个类是否应该作为基类？
// 哪些函数应该是虚函数？
// 是否应该允许子类重写特定行为？
class Shape
{
public:
    virtual ~Shape() = default; // 虚析构函数，允许多态删除

    virtual void draw() const = 0; // 纯虚函数，必须被子类实现
    virtual double area() const = 0;

    // 非虚函数，定义所有形状共有的行为
    void moveBy(double dx, double dy);
};

class Circle : public Shape
{
public:
    explicit Circle(double radius);

    // 实现基类的纯虚函数
    void draw() const override;
    double area() const override;

private:
    double radius;
    Point center;
};

// 6. 类型转换
// 关键问题：

// 是否应该支持到其他类型的转换？
// 是否应该支持从其他类型的转换？
// 这些转换应该是显式的还是隐式的？
class Rational
{
public:
    // 从整数到Rational的转换（显式）
    explicit Rational(int num, int den = 1);

    // 从Rational到double的转换（显式）
    explicit operator double() const
    {
        return static_cast<double>(numerator) / denominator;
    }

private:
    int numerator;
    int denominator;
};

// 使用
Rational r(3, 2);                  // 3/2
double d = static_cast<double>(r); // 需要显式转换

// 7. 操作符重载
// 关键问题：

// 哪些操作符对这个类有意义？
// 操作符的语义应该是什么？
// 操作符应该是成员函数还是非成员函数？
class Complex
{
public:
    Complex(double re = 0, double im = 0);

    // 成员操作符
    Complex &operator+=(const Complex &rhs);
    Complex &operator-=(const Complex &rhs);

private:
    double re, im;
};

// 非成员操作符（基于成员操作符实现）
Complex operator+(Complex lhs, const Complex &rhs)
{
    return lhs += rhs; // 复用operator+=
}

Complex operator-(Complex lhs, const Complex &rhs)
{
    return lhs -= rhs; // 复用operator-=
}

// 8. 标准函数的行为
// 关键问题：

// 标准库函数如何处理这个类型？
// 是否需要特殊的内存管理？
// 是否需要自定义哈希函数或比较函数？
class Customer
{
public:
    // 常规构造和操作...

    // 自定义比较操作
    bool operator==(const Customer &rhs) const;
};

// 为Customer提供哈希支持（C++11及以后）
namespace std
{
    template <>
    struct hash<Customer>
    {
        size_t operator()(const Customer &c) const
        {
            // 自定义哈希实现
            return hash<string>()(c.getName()) ^ hash<int>()(c.getId());
        }
    };
}

// 9. 通用函数的效率
// 关键问题：

// 类的操作有多高效？
// 哪些操作是昂贵的？
// 如何优化常见操作？
class Matrix
{
public:
    // 提供高效的移动操作
    Matrix(Matrix &&rhs) noexcept;
    Matrix &operator=(Matrix &&rhs) noexcept;

    // 避免不必要的拷贝
    void transpose(); // 原地转置，而不是返回新矩阵

    // 提供视图而非拷贝
    MatrixView subMatrix(size_t startRow, size_t startCol,
                         size_t rows, size_t cols);
};

// 10. 类的可扩展性
// 关键问题：

// 这个类将来可能如何演变？
// 哪些部分应该是可定制的？
// 是否应该使用策略模式或其他设计模式？
class TextFormatter
{
public:
    // 使用策略模式允许自定义行为
    void setLineBreakStrategy(std::unique_ptr<LineBreakStrategy> strategy);
    void setHyphenationStrategy(std::unique_ptr<HyphenationStrategy> strategy);

    // 核心功能
    std::string format(const std::string &text);

private:
    std::unique_ptr<LineBreakStrategy> lineBreakStrategy;
    std::unique_ptr<HyphenationStrategy> hyphenationStrategy;
};